package com.flute.tools.util.performance;

import java.util.Arrays;
import java.util.HashMap;

import com.flute.tools.util.collection.Accumulator;

public class PerformanceResult {
	private Accumulator<TimeScope> acc;
	private Accumulator<TimeScope> detailAcc;
	private HashMap<Integer, TimeRecord> records;
	private long bytes;
	private Long[] times;
	private int printCount;
	private long startTime;

	public Long[] getTimes() {
		return times;
	}

	public void setTimes(Long[] times) {
		this.times = times;
	}

	public int getPrintCount() {
		return printCount;
	}

	public void setPrintCount(int printCount) {
		if (acc == null) {
			inital();
		}
		this.printCount = printCount;
	}

	private void inital() {
		this.acc = new Accumulator<TimeScope>();
		this.detailAcc = new Accumulator<TimeScope>();
		this.records = new HashMap<Integer, TimeRecord>();
	}

	public PerformanceResult(Long[] times, int printCount) {
		this.printCount = printCount;
		this.times = times;
		inital();
	}

	public synchronized void record(long time, int status, long bytes) {
		if (startTime == 0) {
			startTime = System.currentTimeMillis();
		}
		this.bytes = this.bytes + bytes;
		acc.addKey(getTimeScope(time));
		detailAcc.addKey(getDetailTimeScope(time));

		if (!records.containsKey(status)) {
			records.put(status, new TimeRecord());
		}

		records.get(status).addTime(time);
	}

	public long getCount() {
		int count = acc.getAllCount();
		if (count % printCount == 0) {
			System.out.println(count + " requests completed.");
			System.out.println(getReport());
			System.out.println("\n\n\n");
		}
		return count;
	}

	private TimeScope getDetailTimeScope(long time) {
		int pos = -1;
		for (int i = 0; i < 1000; i++) {
			if (time < i * 10) {
				pos = i;
				break;
			}
		}

		if (pos == 0) {
			return new TimeScope(0, 10);
		} else if (pos == -1) {
			return new TimeScope(10000, 1000000);
		} else {
			return new TimeScope((pos - 1) * 10, pos * 10);
		}
	}

	private TimeScope getTimeScope(long time) {
		int pos = -1;
		for (int i = 0; i < times.length; i++) {
			if (time < times[i]) {
				pos = i;
				break;
			}
		}

		if (pos == 0) {
			return new TimeScope(0, times[0]);
		} else if (pos == -1) {
			return new TimeScope(times[times.length - 1], 1000000);
		} else {
			return new TimeScope(times[pos - 1], times[pos]);
		}
	}

	public String getReport() {
		StringBuffer sb = new StringBuffer();
		sb.append("Performance Test Report:\n\n");

		try {

			sb.append("响应时间列表:\n");

			TimeScope[] tslist = acc.getKeys().toArray(new TimeScope[] {});

			Arrays.sort(tslist);
			for (TimeScope ts : tslist) {
				sb.append(ts.getLow() + "-" + ts.getUp() + ": "
						+ acc.getCount(ts));
				sb.append("\n");
			}

			sb.append("\n响应时间百分比:\n");
			tslist = detailAcc.getKeys().toArray(new TimeScope[] {});
			Arrays.sort(tslist);
			int total = 0;
			int current = 0;
			for (TimeScope ts : tslist) {
				total = total + detailAcc.getCount(ts);
				if (total * 100 / detailAcc.getAllCount() >= 50 && current < 50) {
					sb.append("50%: " + ts.getUp() + "ms\n");
					current = 50;
				} else if (total * 100 / detailAcc.getAllCount() >= 66
						&& current < 66) {
					sb.append("66%: " + ts.getUp() + "ms\n");
					current = 66;
				} else if (total * 100 / detailAcc.getAllCount() >= 75
						&& current < 75) {
					sb.append("76%: " + ts.getUp() + "ms\n");
					current = 75;
				} else if (total * 100 / detailAcc.getAllCount() >= 80
						&& current < 80) {
					sb.append("80%: " + ts.getUp() + "ms\n");
					current = 80;
				} else if (total * 100 / detailAcc.getAllCount() >= 90
						&& current < 90) {
					sb.append("90%: " + ts.getUp() + "ms\n");
					current = 90;
				} else if (total * 100 / detailAcc.getAllCount() >= 95
						&& current < 95) {
					sb.append("95%: " + ts.getUp() + "ms\n");
					current = 95;
				} else if (total * 100 / detailAcc.getAllCount() >= 98
						&& current < 98) {
					sb.append("98%: " + ts.getUp() + "ms\n");
					current = 98;
				} else if (total * 100 / detailAcc.getAllCount() >= 99
						&& current < 99) {
					sb.append("99%: " + ts.getUp() + "ms\n");
					current = 99;
				} else if (total * 100 / detailAcc.getAllCount() >= 100
						&& current < 100) {
					sb.append("100%: " + ts.getUp() + "ms\n");
					current = 100;
				}
			}

			sb.append("\n平均响应速度:\n");
			for (Integer status : records.keySet()) {
				sb.append(status + ": " + records.get(status).getAverage()
						+ "  total:" + records.get(status).getTotal()
						+ "  count:" + records.get(status).getCount());
				sb.append("\n");
			}
			sb.append("\n");

			sb.append("每秒事务数量: ");
			long allt = 0;
			long allc = 0;
			for (Integer status : records.keySet()) {
				allt = allt + records.get(status).getTotal();
				allc = allc + records.get(status).getCount();
			}

			double time = Double
					.valueOf(System.currentTimeMillis() - startTime);
			sb.append(Double.valueOf(1000 * allc) / time);
			sb.append("\n\n");

			sb.append("每秒网络传输："
					+ (Double.valueOf(bytes) / Double.valueOf(8) / time)
					+ "(KByte).");

		} catch (Exception e) {
			e.printStackTrace();
		}
		return sb.toString().trim();
	}
}
